//! Parser for NRC language

use crate::ast::*;
use crate::error::{CompilerError, Location, Result};
use crate::lexer::token::{Token, TokenWithLocation};
use crate::lexer::Lexer;
use std::collections::VecDeque;

pub mod decl_parser;
pub mod expr_parser;
pub mod stmt_parser;
pub mod type_parser;

use decl_parser::*;
use expr_parser::parse_expression;
pub use stmt_parser::parse_statement;
use type_parser::*;

/// Parser for NRC language
pub struct Parser {
    /// Lexical analyzer
    lexer: Lexer,
    /// Current token
    current: Option<TokenWithLocation>,
    /// Token buffer for lookahead
    buffer: VecDeque<TokenWithLocation>,
    /// Source file information
    source_info: SourceInfo,
    /// Counter for generating unique temporary names
    temp_name_counter: usize,
}

/// Snapshot of parser state for speculative parsing
#[derive(Clone)]
struct ParserSnapshot {
    lexer: Lexer,
    current: Option<TokenWithLocation>,
    buffer: VecDeque<TokenWithLocation>,
    temp_name_counter: usize,
}

impl Parser {
    /// Create a new parser for the given source code
    pub fn new(source: String, file_path: Option<String>) -> Self {
        let source_info = SourceInfo {
            file_path,
            source_code: source.clone(),
        };

        Self {
            lexer: Lexer::new(source),
            current: None,
            buffer: VecDeque::new(),
            source_info,
            temp_name_counter: 0,
        }
    }

    /// Parse the entire program
    pub fn parse_program(&mut self) -> Result<Program> {
        let mut declarations = Vec::new();

        // Initialize parser
        self.advance()?;

        // Parse declarations until EOF
        while !self.is_at_end() {
            if let Some(decl) = self.parse_declaration()? {
                declarations.push(decl);
            } else {
                // If no declaration was parsed, advance to avoid infinite loop
                self.advance()?;
            }
        }

        Ok(Program::new(declarations, self.source_info.clone()))
    }

    /// Parse a declaration
    pub fn parse_declaration(&mut self) -> Result<Option<Declaration>> {
        match self.current.as_ref().map(|t| &t.token) {
            Some(Token::Fn) => {
                let func = decl_parser::parse_function_declaration(self)?;
                Ok(Some(Declaration::Function(func)))
            }
            Some(Token::Let) => {
                let var = decl_parser::parse_variable_declaration(self)?;
                Ok(Some(Declaration::Variable(var)))
            }
            Some(Token::Const) => {
                let const_ = decl_parser::parse_constant_declaration(self)?;
                Ok(Some(Declaration::Constant(const_)))
            }
            Some(Token::Type) => {
                // Check if this is a Go-style struct declaration, enum declaration, or trait declaration
                let current_pos = self.current.clone();
                self.advance()?; // consume 'type'

                if let Some(Token::Identifier(name)) = self.peek().map(|t| &t.token) {
                    let type_name = name.clone();
                    self.advance()?; // consume identifier

                    let next_token = self.peek_token_after_generics()?;

                    if matches!(next_token, Some(Token::Struct)) {
                        // This is a Go-style struct declaration
                        let struct_decl =
                            decl_parser::parse_go_style_struct_declaration_from_current(
                                self, type_name,
                            )?;
                        Ok(Some(Declaration::Struct(struct_decl)))
                    } else if matches!(next_token, Some(Token::Enum)) {
                        // This is an enum declaration
                        let enum_decl =
                            decl_parser::parse_enum_declaration_from_current(self, type_name)?;
                        Ok(Some(Declaration::Enum(enum_decl)))
                    } else if matches!(next_token, Some(Token::Trait)) {
                        // This is a trait declaration
                        let trait_decl =
                            decl_parser::parse_trait_declaration_from_current(self, type_name)?;
                        Ok(Some(Declaration::Trait(trait_decl)))
                    } else {
                        // This is a regular type declaration
                        self.current = current_pos; // restore position
                        let decl = decl_parser::parse_type_declaration(self)?;
                        Ok(Some(Declaration::Type(decl)))
                    }
                } else {
                    // This is a regular type declaration
                    self.current = current_pos; // restore position
                    let decl = decl_parser::parse_type_declaration(self)?;
                    Ok(Some(Declaration::Type(decl)))
                }
            }
            Some(Token::Struct) => {
                let struct_ = decl_parser::parse_struct_declaration(self)?;
                Ok(Some(Declaration::Struct(struct_)))
            }
            Some(Token::Import) | Some(Token::From) => {
                let import = decl_parser::parse_import_declaration(self)?;
                Ok(Some(Declaration::Import(import)))
            }
            Some(Token::Impl) => {
                // Check if this is impl Trait for Type syntax
                // Use peek_ahead to check the token after identifier
                if let Some(identifier_token) = self.peek_ahead(1) {
                    if let Token::Identifier(_) = &identifier_token.token {
                        // Check the token after identifier (2 tokens ahead)
                        if let Some(for_token) = self.peek_ahead(2) {
                            if let Token::For = &for_token.token {
                                // This is a trait implementation
                                let trait_impl = decl_parser::parse_trait_impl_declaration(self)?;
                                Ok(Some(Declaration::TraitImpl(trait_impl)))
                            } else {
                                // This is a regular impl Type { ... }
                                let impl_decl = decl_parser::parse_impl_declaration(self)?;
                                Ok(Some(Declaration::Impl(impl_decl)))
                            }
                        } else {
                            // This is a regular impl Type { ... }
                            let impl_decl = decl_parser::parse_impl_declaration(self)?;
                            Ok(Some(Declaration::Impl(impl_decl)))
                        }
                    } else {
                        // This is a regular impl Type { ... }
                        let impl_decl = decl_parser::parse_impl_declaration(self)?;
                        Ok(Some(Declaration::Impl(impl_decl)))
                    }
                } else {
                    // This is a regular impl Type { ... }
                    let impl_decl = decl_parser::parse_impl_declaration(self)?;
                    Ok(Some(Declaration::Impl(impl_decl)))
                }
            }
            _ => Ok(None),
        }
    }

    /// Advance to the next token
    fn advance(&mut self) -> Result<()> {
        if let Some(token) = self.buffer.pop_front() {
            self.current = Some(token);
        } else {
            self.current = self.lexer.next_token()?;
        }
        Ok(())
    }

    /// Peek at the current token
    fn peek(&self) -> Option<&TokenWithLocation> {
        self.current.as_ref()
    }

    /// Peek at the next token without consuming it
    #[allow(dead_code)]
    fn peek_next(&mut self) -> Result<Option<&TokenWithLocation>> {
        if self.buffer.is_empty() {
            if let Some(token) = self.lexer.next_token()? {
                self.buffer.push_back(token);
            }
        }
        Ok(self.buffer.front())
    }

    /// Peek ahead by n tokens without consuming them
    /// n=0 returns current token, n=1 returns next token, etc.
    fn peek_ahead(&mut self, n: usize) -> Option<&TokenWithLocation> {
        if n == 0 {
            return self.current.as_ref();
        }

        // Fill buffer if needed
        let buffer_index = n - 1;
        while self.buffer.len() <= buffer_index {
            if let Ok(Some(token)) = self.lexer.next_token() {
                self.buffer.push_back(token);
            } else {
                return None;
            }
        }

        self.buffer.get(buffer_index)
    }

    /// Peek at the token following an optional generic parameter list.
    fn peek_token_after_generics(&mut self) -> Result<Option<Token>> {
        if let Some(current) = &self.current {
            if current.token == Token::Less {
                let mut depth = 1;
                let mut offset = 1;
                while let Some(token) = self.peek_ahead(offset) {
                    match token.token {
                        Token::Less => depth += 1,
                        Token::Greater => {
                            depth -= 1;
                            if depth == 0 {
                                offset += 1;
                                break;
                            }
                        }
                        _ => {}
                    }
                    offset += 1;
                }
                return Ok(self.peek_ahead(offset).map(|t| t.token.clone()));
            } else {
                return Ok(Some(current.token.clone()));
            }
        }
        Ok(None)
    }

    /// Check if we're at the end of input
    fn is_at_end(&self) -> bool {
        self.current.is_none()
    }

    /// Check if the current token matches the given token
    fn check(&self, token: &Token) -> bool {
        if let Some(current) = &self.current {
            std::mem::discriminant(&current.token) == std::mem::discriminant(token)
        } else {
            false
        }
    }

    /// Check if the current token matches any of the given tokens
    #[allow(dead_code)]
    fn check_any(&self, tokens: &[Token]) -> bool {
        tokens.iter().any(|token| self.check(token))
    }

    /// Consume the current token if it matches the given token
    fn consume(&mut self, token: &Token) -> Result<bool> {
        if self.check(token) {
            self.advance()?;
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Consume the current token if it matches any of the given tokens
    fn consume_any(&mut self, tokens: &[Token]) -> Result<Option<Token>> {
        for token in tokens {
            if self.check(token) {
                let consumed = token.clone();
                self.advance()?;
                return Ok(Some(consumed));
            }
        }
        Ok(None)
    }

    /// Expect the current token to match the given token
    fn expect(&mut self, token: &Token) -> Result<()> {
        if self.check(token) {
            self.advance()?;
            Ok(())
        } else {
            let location = self
                .current
                .as_ref()
                .map(|t| Location::new(t.line, t.column, t.offset))
                .unwrap_or(Location::new(0, 0, 0));
            Err(CompilerError::syntax(
                location.line,
                location.column,
                format!(
                    "Expected {:?}, found {:?}",
                    token,
                    self.current.as_ref().map(|t| &t.token)
                ),
            ))
        }
    }

    /// Expect the current token to match any of the given tokens
    #[allow(dead_code)]
    fn expect_any(&mut self, tokens: &[Token]) -> Result<Token> {
        if let Some(token) = self.consume_any(tokens)? {
            Ok(token)
        } else {
            let location = self
                .current
                .as_ref()
                .map(|t| Location::new(t.line, t.column, t.offset))
                .unwrap_or(Location::new(0, 0, 0));
            let expected = tokens
                .iter()
                .map(|t| format!("{:?}", t))
                .collect::<Vec<_>>()
                .join(" or ");
            Err(CompilerError::syntax(
                location.line,
                location.column,
                format!(
                    "Expected {}, found {:?}",
                    expected,
                    self.current.as_ref().map(|t| &t.token)
                ),
            ))
        }
    }

    /// Get the current token's location
    fn current_location(&self) -> Location {
        self.current
            .as_ref()
            .map(|t| Location::new(t.line, t.column, t.offset))
            .unwrap_or(Location::new(0, 0, 0))
    }

    /// Take a lightweight snapshot of the parser state
    fn snapshot(&self) -> ParserSnapshot {
        ParserSnapshot {
            lexer: self.lexer.clone(),
            current: self.current.clone(),
            buffer: self.buffer.clone(),
            temp_name_counter: self.temp_name_counter,
        }
    }

    /// Restore the parser to a previously captured snapshot
    fn restore(&mut self, snapshot: ParserSnapshot) {
        self.lexer = snapshot.lexer;
       	self.current = snapshot.current;
        self.buffer = snapshot.buffer;
        self.temp_name_counter = snapshot.temp_name_counter;
    }

    /// Determine if a `?` token starts a conditional (ternary) expression
    fn question_starts_conditional(&mut self) -> Result<bool> {
        let snapshot = self.snapshot();
        let result = (|| -> Result<bool> {
            self.advance()?; // consume '?'
            let has_true_expr = match parse_expression(self)? {
                Some(_) => true,
                None => return Ok(false),
            };
            if !has_true_expr {
                return Ok(false);
            }
            Ok(self.consume(&Token::Colon)?)
        })();
        self.restore(snapshot);
        match result {
            Ok(value) => Ok(value),
            Err(_) => Ok(false),
        }
    }

    /// Generate a unique temporary variable name with the given prefix
    pub(crate) fn next_temp_name(&mut self, prefix: &str) -> String {
        let name = format!("__{}_{}", prefix, self.temp_name_counter);
        self.temp_name_counter += 1;
        name
    }

    /// Synchronize the parser after an error
    #[allow(dead_code)]
    fn synchronize(&mut self) -> Result<()> {
        self.advance()?;

        while !self.is_at_end() {
            if let Some(current) = &self.current {
                match &current.token {
                    Token::Semicolon => {
                        self.advance()?;
                        return Ok(());
                    }
                    Token::Fn
                    | Token::Var
                    | Token::Const
                    | Token::Type
                    | Token::Struct
                    | Token::Import => {
                        return Ok(());
                    }
                    _ => {
                        self.advance()?;
                    }
                }
            }
        }

        Ok(())
    }
}

/// Parse a declaration
#[allow(dead_code)]
fn parse_declaration(parser: &mut Parser) -> Result<Option<Declaration>> {
    if parser.is_at_end() {
        return Ok(None);
    }

    match parser.peek() {
        Some(token) => match &token.token {
            Token::Fn => {
                let decl = parse_function_declaration(parser)?;
                Ok(Some(Declaration::Function(decl)))
            }
            Token::Var => {
                let decl = parse_variable_declaration(parser)?;
                Ok(Some(Declaration::Variable(decl)))
            }
            Token::Const => {
                let decl = parse_constant_declaration(parser)?;
                Ok(Some(Declaration::Constant(decl)))
            }
            Token::Type => {
                let decl = parse_type_declaration(parser)?;
                Ok(Some(Declaration::Type(decl)))
            }
            Token::Struct => {
                let decl = parse_struct_declaration(parser)?;
                Ok(Some(Declaration::Struct(decl)))
            }
            Token::Import => {
                let decl = parse_import_declaration(parser)?;
                Ok(Some(Declaration::Import(decl)))
            }
            _ => {
                // Try to parse as an expression statement
                if let Some(expr) = parse_expression(parser)? {
                    let _stmt = crate::ast::stmt::Statement::Expression(expr);
                    // Convert expression statement to variable declaration if it's an assignment
                    // This is a simplified approach - in a real parser, you'd handle this differently
                    Ok(None)
                } else {
                    Ok(None)
                }
            }
        },
        None => Ok(None),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parser_creation() {
        let source = "func main() { return 42; }".to_string();
        let parser = Parser::new(source, Some("test.n".to_string()));
        assert!(parser.current.is_none());
    }

    #[test]
    fn test_parser_advance() {
        let source = "func main()".to_string();
        let mut parser = Parser::new(source, None);
        parser.advance().unwrap();

        assert!(parser.current.is_some());
        assert_eq!(parser.current.as_ref().unwrap().token, Token::Fn);
    }

    #[test]
    fn test_parser_check() {
        let source = "func main()".to_string();
        let mut parser = Parser::new(source, None);
        parser.advance().unwrap();

        assert!(parser.check(&Token::Fn));
        assert!(!parser.check(&Token::Var));
    }

    #[test]
    fn test_parser_consume() {
        let source = "func main()".to_string();
        let mut parser = Parser::new(source, None);
        parser.advance().unwrap();

        assert!(parser.consume(&Token::Fn).unwrap());
        assert!(!parser.consume(&Token::Var).unwrap());
    }
}
